package com.qqn.acknowledge.reflection;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @ClassName: ReflectVisit
 * @Description: ReflectVisit
 * @Author: 刘神仙
 * @Date: 2025-03-25 21:15
 */
public class ReflectVisit2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        // 获取class对象的三种方式
        // 第一种  类.class
        // 使用 类.class 不会触发类的初始化，只有在访问类的成员或者访问该类的实例时才会被触发
        // Class<User> userClass = User.class;

        // 第二种 使用对象的
        // User user = new User("Albert", 20);
        // 这里泛型参数用 通配符 因为这个Class对象是在运行时从User实例获取的，而 User实例的具体类型只能在运行时创建和确定
        // 在编译阶段无法准确的判断 Class 对象的确切类型
        // Class<?> clazz = user.getClass();

        // 第三种 使用 Class的 forName 静态方法，这种方法用于在运行时动态加载指定的类，并返回该类的 Class 对象实例，
        // 通常用于类名在编译时不可知的场景中
        // 通过这种方法获取的类的 Class 对象时会立即触发类的初始化，类的静态初始化块 static 块会被执行
        Class<?> clazz = Class.forName("com.qqn.acknowledge.reflection.User");
        // 接下来首先关注 类层面的操作，包括查看和修改静态字段的值，以及调用静态方法
        Field field = clazz.getDeclaredField("publicStaticField");
        System.out.println(field.get(null));// 操作的是静态字段的值，所以不需要类的实例，参数可以设置为null
        field = clazz.getDeclaredField("privateStaticField");
        field.setAccessible(true); // 私有的无权访问，为了能够访问可以通过这个设置访问权限
        field.set(null, 100);
        System.out.println(field.get(null));

        // 访问静态方法
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }

        Method method = clazz.getDeclaredMethod("myPublicStaticMethod");
        method.invoke(null);
        method = clazz.getDeclaredMethod("myPrivateStaticMethod");
        method.setAccessible(true);
        method.invoke(null);
        // 指定带参数的方法 表示获取 参数为 String 的 myPrivateStaticMethod 方法
        method = clazz.getDeclaredMethod("myPrivateStaticMethod", String.class);
        method.setAccessible(true);
        method.invoke(null, "Hi there");

    }
}
